#include <iostream>
#include <sys/stat.h>
#include <string>
#include <string.h>
#include <stdio.h>

#include "sdl.h"
#include "opencl.h"
#include "expression.h"

using namespace std;

static char *loadSourceFile(char *fn);
static std::string stringReplace(std::string &s,
					  std::string toReplace,
					  std::string replaceWith);

int main(int argc, char **argv) {
	int w = 512, h = 512;
	char *fn = NULL;
	char defaultFn[] = "brotkernel.cl";
	char skeletonFn[] = "kernel.cl";
	char *source = NULL;
	
	if (argc > 1) {
		std::string code = compile(argv[argc - 1]);
		cout << code << endl;
		source = loadSourceFile(skeletonFn);
		
		string toReplace("// LOOP BODY");
		string skeleton(source);
		delete[] source;
		
		stringReplace(skeleton, toReplace, code);
		
		source = new char[skeleton.length() + 1];
		strcpy(source, skeleton.c_str());
	}
	
	if (initSDL(w, h) != 0) {
		cerr << "error initialising SDL\n";
		return 1;
	}

	if (initOpenCL() != 0) {
		cerr << "error initialising openCL\n";
		return 1;
	}
	
	if (source == NULL) {
		if (fn == NULL) {
			fn = defaultFn;
		}
		cout << "loading default fractal source" << endl;
		source = loadSourceFile(fn);
	}
	
	buildProgram(source);
	
	mainSDL();
	
	delete[] source;
	
	finiProgram();
	
	finiOpenCL();
	
	finiSDL();

	return 0;
}

static char *loadSourceFile(char *fn) {
	struct stat fstats;
	FILE *file;
	char *source;
	size_t size;
	
	// get file size
	if (stat(fn, &fstats) == 0) {
		size = fstats.st_size;
	} else {
		cerr << "failed to stat file: " << fn << endl;
		perror("stat");
		return NULL;
	}
	
	source = new char[size+1];
	
	file = fopen(fn, "rb");
	if (file == NULL) {
		cerr << "failed to open file: " << fn << endl;
		perror("fopen");
		return NULL;
	}
	
	size_t c;
	c = fread(source, 1, size, file);
	if (c != size) {
		cerr << "file read error. " << c << " of " << size << " bytes read" << endl;
		perror("fread");
		return NULL;
	}
	
	source[size] = '\0';
	
	fclose(file);
	
	return source;
}

static std::string stringReplace(std::string &s,
					  std::string toReplace,
					  std::string replaceWith) {
	size_t pos;
	while ((pos = s.find(toReplace)) != string::npos) {
		size_t pos = s.find(toReplace);
		s.replace(pos, toReplace.length(), replaceWith);
	}
	return s;
}
